package org.origin.centre.support.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 基础工具
 *
 * @author ferret
 * @version 2024-05-08
 */
@SuppressWarnings("unused")
public final class BasicUtil {
    private final static Logger logger = LoggerFactory.getLogger(BasicUtil.class);
    private static final Pattern NUMBER_PATTERN = Pattern.compile("^-?\\d+(\\.\\d+)?$");

    /**
     * 是否是 window 系统
     *
     * @return 否是 window 系统
     */
    public static boolean isWindow() {
        String os = System.getProperty("os.name");
        return os != null && os.toLowerCase().startsWith("win");
    }

    /**
     * 获取所有的class的属性
     *
     * @param clazz Class
     * @return Fields
     */
    public static List<Field> getAllFiles(Class<?> clazz) {
        if (clazz == null) {
            return null;
        }
        List<Field> result = new ArrayList<>();
        Stack<Class<?>> stack = new Stack<>();
        stack.push(clazz);
        for (int i = 0; i < 10000; i++) {
            if (!stack.isEmpty()) {
                Class<?> cls = stack.pop();
                if (cls != null) {
                    Field[] fields = cls.getDeclaredFields();
                    for (Field field : fields) {
                        if (field != null) {
                            result.add(field);
                        }
                    }
                    Class<?> superclass = cls.getSuperclass();
                    if (superclass != null) {
                        stack.push(superclass);
                    }
                }
            } else {
                return result;
            }
        }
        throw new IllegalArgumentException("超过最大遍历次数！");
    }

    /**
     * 获取所有的class的属性
     *
     * @param clazz Class
     * @return Fields
     */
    public static Map<String, Field> getAllFilesMap(Class<?> clazz) {
        if (clazz == null) {
            return null;
        }
        Map<String, Field> result = new LinkedHashMap<>();
        Stack<Class<?>> stack = new Stack<>();
        stack.push(clazz);
        for (int i = 0; i < 10000; i++) {
            if (!stack.isEmpty()) {
                Class<?> cls = stack.pop();
                if (cls != null) {
                    Field[] fields = cls.getDeclaredFields();
                    for (Field field : fields) {
                        if (field != null) {
                            if (!result.containsKey(field.getName())) {
                                result.put(field.getName(), field);
                            }
                        }
                    }
                    Class<?> superclass = cls.getSuperclass();
                    if (superclass != null) {
                        stack.push(superclass);
                    }
                }
            } else {
                return result;
            }
        }
        throw new IllegalArgumentException("超过最大遍历次数！");
    }

    /**
     * 获取所有的 Annotation class的属性
     *
     * @param clazz Class
     * @return Fields
     */
    public static List<Field> getAllFilesByAnnotation(Class<?> clazz, Class<? extends Annotation> ann) {
        if (clazz == null) {
            return null;
        }
        if (ann == null) {
            return null;
        }
        List<Field> result = new ArrayList<>();
        Stack<Class<?>> stack = new Stack<>();
        stack.push(clazz);
        for (int i = 0; i < 10000; i++) {
            if (!stack.isEmpty()) {
                Class<?> cls = stack.pop();
                if (cls != null) {
                    Field[] fields = cls.getDeclaredFields();
                    for (Field field : fields) {
                        if (field != null && field.isAnnotationPresent(ann)) {
                            result.add(field);
                        }
                    }
                    Class<?> superclass = cls.getSuperclass();
                    if (superclass != null) {
                        stack.push(superclass);
                    }
                }
            } else {
                return result;
            }
        }
        throw new IllegalArgumentException("超过最大遍历次数！");
    }

    /**
     * 通过字段名获取字段
     *
     * @param clazz Class
     * @param name  字段名
     * @return 属性
     */
    public static Field getFieldByName(Class<?> clazz, String name) {
        if (clazz == null) {
            return null;
        }
        if (isNotBlank(name)) {
            return null;
        }
        Stack<Class<?>> stack = new Stack<>();
        stack.push(clazz);
        for (int i = 0; i < 10000; i++) {
            if (!stack.isEmpty()) {
                Class<?> cls = stack.pop();
                if (cls != null) {
                    Field[] fields = cls.getDeclaredFields();
                    for (Field field : fields) {
                        if (field != null && field.getName().equals(name)) {
                            return field;
                        }
                    }
                    Class<?> superclass = cls.getSuperclass();
                    if (superclass != null) {
                        stack.push(superclass);
                    }
                }
            } else {
                return null;
            }
        }
        throw new IllegalArgumentException("超过最大遍历次数！");
    }

    /**
     * 通过字段名获取字段值
     *
     * @param object Object
     * @param name   字段名
     * @return 字段值
     */
    public static Object getFieldValue(Object object, String name) {
        try {
            if (object != null) {
                Field field = getFieldByName(object.getClass(), name);
                if (field != null) {
                    field.setAccessible(true);
                    return field.get(object);
                }
            }
        } catch (Exception e) {
            logger.error(name + "获取字段值失败：", e);
        }
        return null;
    }

    /**
     * 获取所有的class的属性
     *
     * @param clazz Class
     * @return Fields
     */
    public static List<Method> getPublicMethod(Class<?> clazz) {
        if (clazz == null) {
            return null;
        }
        Method[] methods = clazz.getMethods();
        return toList(methods);
    }

    /**
     * 通过字段名获取其对应的getter方法
     *
     * @param clazz 要查找的类
     * @param name  要查找的getter方法名（不包含get）
     * @return 找到的getter方法，如果未找到或输入参数无效则返回null
     */
    public static Method getMethodByName(Class<?> clazz, String name) {
        // 检查类对象是否为null
        if (clazz == null) {
            return null;
        }
        // 检查方法名是否为空或不明确
        if (isNotBlank(name)) {
            return null;
        }
        String getName = "get" + upperFirst(name);
        try {
            // 如果方法名以"get"开头，尝试获取完整的getter方法并返回
            return clazz.getMethod(getName);
        } catch (Exception e) {
            // 如果查找过程中发生异常，记录错误信息
            logger.error(getName + "获取方法失败：", e);
        }
        // 如果未找到方法或出现异常，返回null
        return null;
    }

    /**
     * 通过字段名获取字段值
     *
     * @param object Object
     * @param name   字段名
     * @return 字段值
     */
    public static Object geMethodValue(Object object, String name) {
        try {
            if (object != null) {
                Method method = getMethodByName(object.getClass(), name);
                if (method != null) {
                    return method.invoke(object);
                }
            }
        } catch (Exception e) {
            logger.error(name + "通过方法获取数据值失败：", e);
        }
        return null;
    }

    /**
     * Array转List
     */
    @SuppressWarnings({"UseBulkOperation", "ManualArrayToCollectionCopy"})
    public static <T> List<T> toList(T[] array) {
        List<T> result = new ArrayList<>();
        if (array != null && array.length > 0) {
            for (T item : array) {
                result.add(item);
            }
        }
        return result;
    }

    /**
     * List转Array
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] toArray(List<T> list, Class<T> componentType) {
        if (list != null && list.size() > 0) {
            return list.toArray((T[]) Array.newInstance(componentType, list.size()));
        }
        return (T[]) Array.newInstance(componentType, 0);
    }

    /**
     * 文件路径连接
     *
     * @param paths 路径
     * @return 连接后的路径
     */
    public static String getPath(String... paths) {
        // 使用File.separator确保路径分隔符的系统独立性
        StringBuilder builder = new StringBuilder();
        if (paths != null && paths.length > 0) {
            // 预先分配StringBuilder的容量，减少扩容操作
            builder.setLength(paths.length * 16); // 假设平均路径长度为16字符
            for (String path : paths) {
                if (path != null && !path.isEmpty()) {
                    // 检查并添加路径分隔符
                    if (builder.length() > 0 && builder.charAt(builder.length() - 1) != File.separatorChar) {
                        builder.append(File.separatorChar);
                    }
                    builder.append(path);
                }
            }
        }
        return builder.toString()
                .replaceAll("[\\\\/]+", File.separator);
    }

    /**
     * 生成文件
     *
     * @param filepath 文件路径
     * @param context  文件内容
     */
    public static void writeFile(String filepath, String context) {
        FileOutputStream fos = null;
        try {
            File file = new File(filepath);
            File parent = file.getParentFile();
            if (!parent.exists()) {
                boolean mkdirs = parent.mkdirs();
            }
            if (!file.exists()) {
                boolean newFile = file.createNewFile();
            }
            byte[] bytes = context.getBytes();
            //是字节的长度，不是字符串的长度
            int b = bytes.length;
            fos = new FileOutputStream(file);
            fos.write(bytes, 0, b);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            flush(fos);
            close(fos);
        }
    }

    /**
     * 读取文件内容
     *
     * @param filepath 文件路径
     * @return 文件内容
     */
    public static String readFile(String filepath) {
        return readFile(new File(filepath));
    }

    /**
     * 读取文件内容
     *
     * @param file 文件
     * @return 文件内容
     */
    public static String readFile(File file) {
        FileReader fileReader = null;
        BufferedReader reader = null;
        StringBuilder sbf = new StringBuilder();
        try {
            if (file.isFile() && file.exists()) {
                fileReader = new FileReader(file);
                reader = new BufferedReader(fileReader);
                String tempStr;
                while ((tempStr = reader.readLine()) != null) {
                    sbf.append(tempStr);
                    sbf.append("\n");
                }
                reader.close();
                return sbf.toString();
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) reader.close();
            } catch (Exception e1) {
                e1.printStackTrace();
            }
            try {
                if (fileReader != null) fileReader.close();
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 通过正则匹配表达式获取第一个数据
     *
     * @param regex 正则表达式
     * @param src   资源字符串
     * @return 第一个数据
     */
    public static String findByRegex(String src, String regex) {
        return findByRegex(Pattern.compile(regex), src);
    }

    /**
     * 通过正则匹配表达式获取第一个数据
     *
     * @param pattern 正则表达式
     * @param src     资源字符串
     * @return 第一个数据
     */
    public static String findByRegex(Pattern pattern, String src) {
        Matcher matcher = pattern.matcher(src);
        while (matcher.find()) {
            try {
                return matcher.group();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 通过正则匹配表达式获取数据集
     *
     * @param regex 正则表达式
     * @param src   资源字符串
     * @return 数据集
     */
    public static List<String> findsByRegex(String src, String regex) {
        return findsByRegex(Pattern.compile(regex), src);
    }

    /**
     * 通过正则匹配表达式获取数据集
     *
     * @param pattern 正则表达式
     * @param src     资源字符串
     * @return 数据集
     */
    public static List<String> findsByRegex(Pattern pattern, String src) {
        Matcher matcher = pattern.matcher(src);
        List<String> list = new ArrayList<>();
        while (matcher.find()) {
            try {
                String group = matcher.group();
                if (group != null) list.add(group);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return list;
    }

    /**
     * 通过正则匹配表达式获取第一个数据
     *
     * @param regex 正则表达式
     * @param src   资源字符串
     * @return 第一个数据
     */
    public static String findByRegexGroup(String src, String regex, int group) {
        Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(src);
        if (matcher.find()) {
            try {
                return matcher.group(group);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 获取到 2 个字符串之间的内容-包含起始字符和结束字符
     *
     * @param src   源字符串
     * @param start 起始字符
     * @param end   结束字符
     * @return 2 个字符串之间的内容
     */
    public static String getStartToEnd(String src, String start, String end) {
        return findByRegex(src, escapeWord(start) + "[\\s\\S]*?" + escapeWord(end));
    }

    /**
     * 获取到 2 个字符串之间的内容
     *
     * @param src   源字符串
     * @param start 起始字符
     * @param end   结束字符
     * @return 2 个字符串之间的内容
     */
    public static String getStartOfEnd(String src, String start, String end) {
        return findByRegex(src, "(?<=" + escapeWord(start) + ")" + "[\\s\\S]*?" + "(?=" + escapeWord(end) + ")");
    }

    /**
     * 转义正则特殊字符 （$()*+.[]?\^{},|）
     *
     * @param keyword 字符
     * @return 新字符串
     */
    public static String escapeWord(String keyword) {
        if (keyword != null && !"".equals(keyword)) {
            String[] fbsArr = {"\\", "$", "(", ")", "*", "+", ".", "[", "]", "?", "^", "{", "}", "|"};
            for (String key : fbsArr) {
                if (keyword.contains(key)) {
                    keyword = keyword.replace(key, "\\" + key);
                }
            }
        }
        return keyword;
    }

    /**
     * md5 加密
     *
     * @param src 预加密字符串
     * @return md5 已加密字符串
     */
    public static String encodeMd5(String src) {
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            // BASE64Encoder base64en = new BASE64Encoder();
            Base64.Encoder encoder = Base64.getEncoder();
            //加密后的字符串
            return new String(encoder.encode(md5.digest(src.getBytes(StandardCharsets.UTF_8))));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * md5 加密
     *
     * @param src 预加密字符串
     * @return md5 已加密字符串
     */
    public static String encodeMD5(String src) {
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(src.getBytes());
            int i;
            byte[] digest = md5.digest();
            StringBuilder buf = new StringBuilder();
            for (byte b : digest) {
                i = b;
                if (i < 0) {
                    i += 256;
                }
                if (i < 16) {
                    buf.append("0");
                }
                buf.append(Integer.toHexString(i));
            }
            return buf.toString().toUpperCase();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取模板中所有变量的名称。
     * 该方法通过正则表达式匹配模板字符串中的所有变量，这些变量以"${"开头，"}"结尾。
     *
     * @param template 模板字符串，其中可能包含多个变量。
     * @return 返回一个包含所有变量名称的集合，集合中的每个元素都是一个字符串。
     */
    public static Set<String> getTemplateNames(String template) {
        String regex1 = escapeWord("${") + "[\\s\\S]*?" + escapeWord("}");
        String regex2 = escapeWord("${") + "[\\s\\S]*?" + escapeWord("}");
        return new HashSet<>(findsByRegex(String.format("(%s)|(%s)", regex1, regex2), template));
    }

    /**
     * 按长度分割字符串
     * 将字符串按指定长度进行分割，返回一个包含分割结果的列表。
     * 如果字符串长度小于指定长度，将返回一个只包含原字符串的列表。
     * 如果字符串长度等于指定长度，将返回一个只包含一个元素（原字符串）的列表。
     * 否则，将字符串分割成多个长度为len的子字符串，并将它们放入列表中。
     * 最后一个子字符串的长度可能小于len，如果剩余字符不足len个。
     *
     * @param str 要分割的字符串
     * @param len 分割的长度，每个子字符串的最大长度
     * @return 一个包含按指定长度分割后的子字符串的列表
     */
    public static List<String> split(String str, int len) {
        List<String> result = new ArrayList<>();
        if (str == null || str.isEmpty()) {
            return result;
        }
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            String value = str.substring(i, i + 1);
            int length = value.getBytes(StandardCharsets.UTF_8).length;
            int newLength = builder.toString().getBytes(StandardCharsets.UTF_8).length;
            if (newLength + length > len) {
                result.add(builder.toString());
                builder = new StringBuilder();
            }
            builder.append(value);
            if (i == str.length() - 1) {
                result.add(builder.toString());
                return result;
            }
        }
        return result;
    }

    /**
     * 将给定的字符串使用Base64编码转换为其Base64表示形式。
     * Base64编码是一种常用的二进制数据转文本字符串的编码方式，常用于在HTTP请求中传输二进制数据。
     *
     * @param str 需要转换为Base64编码的原始字符串
     * @return 返回Base64编码后的字符串
     */
    public static String toBase64(String str) {
        if (str == null) {
            return null;
        }
        return Base64.getEncoder()
                .encodeToString(str.getBytes(
                        StandardCharsets.UTF_8));
    }

    /**
     * 判断给定的Class对象是否代表Java的基本类型、常见类型或枚举类型。
     * 包括八大基本类型及其包装类型，String，Calendar，CharSequence，Number，Date，Time，Duration，以及枚举类型。
     *
     * @param cls 需要判断的Class对象
     * @return 如果是基本类型、常见类型或枚举类型则返回true，否则返回false
     */
    public static boolean isBaseType(Class<?> cls) {
        return cls != null && (cls.isPrimitive() ||
                cls.equals(Boolean.class) ||
                cls.equals(Integer.class) ||
                cls.equals(Character.class) ||
                cls.equals(Byte.class) ||
                cls.equals(Short.class) ||
                cls.equals(Double.class) ||
                cls.equals(Long.class) ||
                cls.equals(Float.class) ||
                cls.equals(String.class) ||
                java.lang.CharSequence.class.isAssignableFrom(cls) ||
                java.lang.Number.class.isAssignableFrom(cls) ||
                java.util.Calendar.class.isAssignableFrom(cls) ||
                java.util.Date.class.isAssignableFrom(cls) ||
                java.sql.Date.class.isAssignableFrom(cls) ||
                java.sql.Time.class.isAssignableFrom(cls) ||
                java.time.Duration.class.isAssignableFrom(cls) ||
                java.net.URI.class.isAssignableFrom(cls) ||
                java.net.URL.class.isAssignableFrom(cls) ||
                cls.isEnum()
        );
    }

    /**
     * 获取当前机器的IP地址。
     * <p>
     * 该方法尝试获取本地主机的IP地址。如果无法获取到有效的IP地址，则返回默认的本地回环地址"127.0.0.1"。
     *
     * @return 当前机器的IP地址字符串。如果无法获取真实的IP地址，则返回"127.0.0.1"。
     */
    public static String getMachineIp() {
        try {
            // 尝试获取本地主机地址
            InetAddress address = InetAddress.getLocalHost();
            // 返回本地主机的IP地址
            return address.getHostAddress();
        } catch (UnknownHostException e) {
            // 在无法获取本地主机地址时，返回默认的回环地址
            return "127.0.0.1";
        }
    }

    /**
     * 将字符串转换为BigDecimal对象。
     *
     * @param str 输入的字符串。
     * @return 如果字符串可以转换为数字，则返回对应的BigDecimal对象；否则返回null。
     */
    public static BigDecimal getBigDecimal(String str) {
        // 判断字符串是否为数字
        if (isNumber(str)) {
            return new BigDecimal(str); // 字符串为数字时，返回对应的BigDecimal对象
        }
        return null; // 字符串不是数字时，返回null
    }

    /**
     * 判断给定的字符串是否表示一个数字（整数或小数）。
     *
     * @param str 待检查的字符串。
     * @return 如果字符串表示一个数字，则返回true；否则返回false。
     */
    public static boolean isNumber(String str) {
        if (str == null) {
            return false;
        }
        Matcher matcher = NUMBER_PATTERN.matcher(str);
        return matcher.matches();
    }

    /**
     * 判断传入的字符串是否为数字。
     *
     * @param str 需要判断的字符串。
     * @return 返回{@code true}如果字符串是数字，否则返回{@code false}。
     */
    public static boolean isNumeric(String str) {
        // 检查字符串是否为null
        if (str == null) {
            return false;
        } else {
            int sz = str.length();
            // 遍历字符串中的每个字符，检查是否都是数字
            for (int i = 0; i < sz; ++i) {
                if (!Character.isDigit(str.charAt(i))) {
                    return false;
                }
            }
            return true;
        }
    }

    /**
     * 刷新输出流
     * 如果输出流非空，则尝试刷新输出流。若刷新失败，记录详细的错误日志。
     *
     * @param outputStream 待刷新的输出流对象
     */
    public static void flush(OutputStream outputStream) {
        if (null != outputStream) {
            try {
                outputStream.flush();
            } catch (IOException e) {
                // 更明确地捕获并处理IOException
                logger.error("在线程 " + Thread.currentThread().getName() + " 中，输出流刷新失败。异常堆栈跟踪如下：", e);
                // 根据具体情况，这里可以考虑是否需要进一步处理异常，例如重新尝试刷新或抛出自定义异常
            } catch (Exception e) {
                // 捕获其他非预期异常
                logger.error("在线程 " + Thread.currentThread().getName() + " 中，输出流刷新时发生非预期异常。异常堆栈跟踪如下：", e);
                // 对于非IO异常，可能需要进一步评估影响并考虑合适的处理策略
            }
        }
    }

    /**
     * 关闭流
     */
    public static void close(Closeable cloneable) {
        if (null != cloneable) {
            try {
                cloneable.close();
            } catch (IOException e) {
                // 更明确地捕获并处理IOException
                logger.error("在线程 " + Thread.currentThread().getName() + " 中，关闭流失败。异常堆栈跟踪如下：", e);
                // 根据具体情况，这里可以考虑是否需要进一步处理异常，例如重新尝试刷新或抛出自定义异常
            } catch (Exception e) {
                // 捕获其他非预期异常
                logger.error("在线程 " + Thread.currentThread().getName() + " 中，关闭流时发生非预期异常。异常堆栈跟踪如下：", e);
                // 对于非IO异常，可能需要进一步评估影响并考虑合适的处理策略
            }
        }
    }

    /**
     * 将字符串的首字母变为大写
     *
     * @param str 字符串
     * @return 首字母大写字符串
     */
    public static String upperFirst(String str) {
        if (str != null) {
            char[] chars = str.toCharArray();
            chars[0] = Character.toUpperCase(chars[0]);
            return String.valueOf(chars);
        }
        return null;
    }

    /**
     * 将字符串的首字母变为小写
     *
     * @param str 字符串
     * @return 首字母小写字符串
     */
    public static String lowerFirst(String str) {
        if (str != null) {
            char[] chars = str.toCharArray();
            chars[0] = Character.toLowerCase(chars[0]);
            return String.valueOf(chars);
        }
        return null;
    }

    /**
     * 驼峰转下划线
     *
     * @param str 转换字符串
     * @return 转换结果
     */
    public static String toUnderline(String str) {
        char UNDERLINE = '_';
        if (str == null || "".equals(str.trim())) {
            return "";
        }
        int len = str.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            if (i == 0) {
                sb.append(Character.toLowerCase(str.charAt(i)));  //统一都转小写
                continue;
            }
            char c = str.charAt(i);
            if (Character.isUpperCase(c)) {
                sb.append(UNDERLINE);
            }
            // sb.append(Character.toUpperCase(c));  //统一都转大写
            sb.append(Character.toLowerCase(c));  //统一都转小写
        }
        return sb.toString();
    }

    /**
     * 下划线转驼峰
     *
     * @param str 转换字符串
     * @return 转换结果
     */
    public static String toCamelCase(String str) {
        char UNDERLINE = '_';
        if (str == null || "".equals(str.trim())) {
            return "";
        }
        str = str.trim().replaceAll("_+", "_");
        int len = str.length();
        StringBuilder sb = new StringBuilder(len);
        boolean flag = false; // "_" 后转大写标志,默认字符前面没有"_"
        for (int i = 0; i < len; i++) {
            char c = str.charAt(i);
            if (c == UNDERLINE) {
                flag = true;
                //标志设置为true,跳过
            } else {
                if (flag) {
                    //表示当前字符前面是"_" ,当前字符转大写
                    sb.append(Character.toUpperCase(str.charAt(i)));
                    flag = false;  //重置标识
                } else {
                    sb.append(Character.toLowerCase(str.charAt(i)));
                }
            }
        }
        return sb.toString();
    }

    /**
     * 获取分页总页数
     *
     * @param total 总数据量
     * @param size  每一页数据量
     * @return 总共分多少页
     */
    public static int getPages(Long total, Integer size) {
        if (total == null || total < 0) total = 0L;
        if (size == null || size <= 0) size = 10;
        return (int) Math.ceil(total * 1.f / size);
    }

    /**
     * 获取指定的实例；没有就会创建并存储
     */
    public static <T> T getInstance(Map<String, T> cacheMap, String name, Supplier<T> supplier) {
        T instance = cacheMap.get(name);
        if (instance == null) {
            instance = supplier.get();
            cacheMap.put(name, instance);
        }
        return instance;
    }

    /**
     * 获取方法上注解
     */
    public static <T extends Annotation> T getAnnotation(Method method, Class<T> cls, boolean throwException) {
        if (method != null && method.isAnnotationPresent(cls)) {
            return method.getAnnotation(cls);
        }
        if (throwException) {
            throw new IllegalArgumentException(cls.getSimpleName() + "该方法没有该注解");
        }
        return null;
    }

    /**
     * 获取类字段注解
     */
    public static <T extends Annotation> T getAnnotation(Field field, Class<T> cls, boolean throwException) {
        if (field != null && field.isAnnotationPresent(cls)) {
            return field.getAnnotation(cls);
        }
        if (throwException) {
            throw new IllegalArgumentException(cls.getSimpleName() + "该字段没有该注解");
        }
        return null;
    }

    /**
     * 获取类上注解
     */
    public static <T extends Annotation> T getAnnotation(Class<?> clazz, Class<T> cls, boolean throwException) {
        if (clazz != null && clazz.isAnnotationPresent(cls)) {
            return clazz.getAnnotation(cls);
        }
        if (throwException) {
            throw new IllegalArgumentException(cls.getSimpleName() + "该类没有该注解");
        }
        return null;
    }

    /**
     * 根据提供的值和函数，以安全的方式获取处理后的结果。
     * 如果提供的值不为null，则使用提供的函数对值进行处理并返回处理结果；
     * 如果值为null，则返回null。
     *
     * @param value    待处理的值，可能为null。
     * @param function 一个函数，用于处理提供的值。该函数应能接受一个与value类型相同的参数，并返回一个R类型的值。
     * @param <T>      输入值的类型。
     * @param <R>      函数处理结果的类型。
     * @return 如果value不为null，返回function.apply(value)的结果；如果value为null，返回null。
     */
    public static <T, R> R getNinValue(T value, Function<T, R> function) {
        // 当value不为null时，应用提供的函数并返回结果；否则返回null
        if (value != null) {
            return function.apply(value);
        }
        return null;
    }

    /**
     * 将非空值传递给提供的消费者接口进行处理。
     *
     * @param value    需要被处理的值，如果为null，则不进行处理。
     * @param consumer 消费者接口，用来接受并处理非空的value。
     * @param <T>      泛型参数，代表value和consumer共同接受的类型。
     */
    public static <T> void setNinValue(T value, Consumer<T> consumer) {
        // 当value不为null时，调用consumer的accept方法处理value
        if (value != null) {
            consumer.accept(value);
        }
    }

    /**
     * 将非空值传递给提供的消费者接口进行处理。
     *
     * @param value    需要被处理的值，如果为null，则不进行处理。
     * @param consumer 消费者接口，用来接受并处理非空的value。
     */
    public static void setBlankValue(String value, Consumer<String> consumer) {
        // 当value不为null时，调用consumer的accept方法处理value
        if (isNotBlank(value)) {
            consumer.accept(value);
        }
    }

    /**
     * 获取给定值或默认值的函数。
     * 如果给定的值为null，则返回默认值；否则返回给定值。
     *
     * @param value      给定的值，其类型为泛型T。
     * @param defaultVal 默认值，当给定值为null时返回该值。
     * @param <T>        泛型标识，表示value和defaultVal的类型。
     * @return 返回非null的给定值或默认值。
     */
    public static <T> T getDefaultVal(T value, T defaultVal) {
        // 判断给定值是否为null，为null则返回默认值，否则返回给定值
        return value == null ? defaultVal : value;
    }

    /**
     * 获取给定值或默认值。
     * 该方法检查提供的字符串是否为空（非blank），如果为空，则返回默认值；否则返回给定的字符串值。
     *
     * @param value      给定的字符串值，需要检查是否为空。
     * @param defaultVal 当给定值为空时，返回的默认值。
     * @return 给定值不为空时返回该值，为空时返回默认值。
     */
    public static String getBlankVal(String value, String defaultVal) {
        // 判断给定值是否为null，为null则返回默认值，否则返回给定值
        return isNotBlank(value) ? value : defaultVal;
    }

    /**
     * 获取到异常中堆栈信息
     *
     * @param e 异常
     * @return 堆栈信息
     */
    public static String getStackTrace(Exception e) {
        try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw, true)) {
            e.printStackTrace(pw);
            return sw.getBuffer().toString();
        } catch (Exception ex) {
            // ignore ex.printStackTrace();
            return null;
        }
    }

    /**
     * 获取uuid
     */
    public static String uuid() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 判断是否不为空
     *
     * @param str 参数
     * @return 是否为空
     */
    public static boolean isNotBlank(String str) {
        return str != null && str.trim().length() > 0;
    }

    /**
     * 判断是否为空
     *
     * @param str 参数
     * @return 是否为空
     */
    public static boolean isBlank(String str) {
        return str == null || str.trim().length() <= 0;
    }

    /**
     * 判断是否一样
     *
     * @param src 参数
     * @return 是否一样
     */
    public static boolean isEquals(String src, String erc) {
        return src != null && src.equals(erc);
    }
}
